#include "QuadTree.h"





QuadTree::QuadTree(int gameLevel)
{
	this->curGameObjects = new map<int, AbstractEntity*>();
	this->GameData = new CGameData();
	getMapData(gameLevel);
	this->buildQuadTreeFromNodes(GameData->nodes);

	this->RootNode->parent = NULL;

	//this->changeMap(L".\\Resources\\Map\\test\\map_QT.txt");
}
QuadTree::~QuadTree()
{

}

void QuadTree::GetListObjectInRect(Rect* rect)
{
	curGameObjects->clear();
	this->RootNode->getObject(curGameObjects, rect);
}

void QuadTree::changeMap(int gameLevel)
{
	//get data from new map
	GameData = new CGameData();
	getMapData(gameLevel);

	//delete all tree map before
	this->RootNode->deleteNode();
	this->buildQuadTreeFromNodes(GameData->nodes);

}

//Add game object to node
// get node by node id from gamedata to insert
void QuadTree::addObjectsToNode(int id, AbstractEntity* obj)
{
	GameData->nodes->at(id)->addGameObjects(obj);
}

void QuadTree::addObjectToQuadTree(AbstractEntity* obj)
{
	this->RootNode->addGameObjects(obj);
}

void QuadTree::buildQuadTreeFromNodes(map<int,CNode*>* nodes)
{
	map<int, CNode*>::iterator it;
	int parentId;
	for(it = nodes->begin(); it != nodes->end(); it++)
	{
		parentId = it->first % 4 == 0 ? it->first/NUM_NODE - 1 : it->first/NUM_NODE;
		if(parentId > 0)
		{
			nodes->at(parentId)->addChild(it->second);
		}
	}
	this->RootNode = nodes->at(1);
}


void QuadTree::getCollistionObjects(AbstractEntity* dyObject, vector<CollistionOutput*>& output)
{
	output.clear();
	if (!dyObject->getAbstractData()->canInteract) {
		return;
	}
	getCollistionObjects(dyObject->getAbstractData()->getRect(), output);
}

void QuadTree::getCollistionObjects(AbstractEntity* dyObject, vector<CollistionOutput*>& output, std::map<int, AbstractEntity*> *entities) {
	output.clear();
	if (!dyObject->getAbstractData()->canInteract) {
		return;
	}
	getCollistionObjects(dyObject->getAbstractData()->getRect(), output, entities);
}

void QuadTree::getCollistionObjects(Rect* rect, vector<CollistionOutput*>& output, std::map<int, AbstractEntity*> *entities) {
	output.clear();
	if(curGameObjects == NULL || curGameObjects->size() == 0)
	{
		return;
	}

	map<int, AbstractEntity*>::iterator it;
	float normalx;
	float normaly;
	float entryTime;

	for(it = entities->begin(); it != entities->end(); it++)
	{
		if(it->second->getAbstractData()->canInteract)
		{
			entryTime = rect->sweptAABB(rect, it->second->getAbstractData()->rect, normalx, normaly);
			//if there was collistion then add collition info to output
			//sort with ascending entryTime 
			if(entryTime >= 0.0f && entryTime < 1.0f)
			{
				if(output.size() == 0 || output.at(output.size() -1)->entryTime <= entryTime)
				{
					output.push_back(new CollistionOutput(it->second, normalx, normaly, entryTime));
				}
				else
				{
					output.insert(output.begin(), new CollistionOutput(it->second, normalx, normaly, entryTime));
				}
			}
		}
	}
}

void QuadTree::getCollistionObjects(Rect* rect, vector<CollistionOutput*>& output)
{
	getCollistionObjects(rect, output, curGameObjects);
}

void QuadTree::getMapData(int gameLevel)
{
	switch (gameLevel)
	{
	case GameLevel1:
		GameData->getMapDataFromFile(MAP1_FILE);
		break;
	case GameLevel2:
		GameData->getMapDataFromFile(MAP2_FILE);
		break;
	case GameLevel3:
		GameData->getMapDataFromFile(MAP3_FILE);
		break;
	default:
		GameData->getMapDataFromFile(MAP1_FILE);
		break;
	}
}
